﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Xml.Serialization;
using FourPartHarmony2;

namespace FourPartHarmonyTestProject
{
    class Tester
    {
        private static Tester instance = null;

        private string modulationLogPath = "C:/work/modulationLog.txt";

        private string qualityOutputPath = "C:/work/quality.txt";
        private double qualityAccum = 0.0;
        private int qualityTestCount = 0;
        private int refCount = 0;

        public static Tester Instance {
            get {
                if (null == instance) {
                    instance = new Tester();
                }
                return instance;
            }
        }

        public void IncRef() {
            ++refCount;
            if (1 == refCount) {
                QualityInit();
            }
        }

        public void DecRef() {
            --refCount;
            if (refCount <= 0) {
                QualityTerm();
            }
        }

        private void QualityInit()
        {
            using (StreamWriter sw = new StreamWriter(File.Open(qualityOutputPath, FileMode.Append))) {
                sw.WriteLine("\r\n{0} started =================================", DateTime.Now);
            }
            qualityAccum = 0.0;
        }

        private void QualityTerm() {
            using (StreamWriter sw = new StreamWriter(File.Open(qualityOutputPath, FileMode.Append))) {
                sw.WriteLine("quality_accum = {0:F2}", qualityAccum);
                if (0 < qualityTestCount) {
                    sw.WriteLine("quality_index = {0:F3}", qualityAccum / qualityTestCount);
                }
            }
        }

        private Music TryLoad2(string path) {
            Music music = null;
            try {
                var s = new XmlSerializer(typeof(MusicSave));
                using (TextReader r = new StreamReader(File.Open(path, FileMode.Open))) {
                    MusicSave ms = (MusicSave)s.Deserialize(r);

                    if (null != ms) {
                        music = ms.ToMusic();
                    }
                }
            } catch (System.Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            return music;
        }

        public Music ReadFphAndCreateMusic(bool checkQuality, string path) {
            var music = TryLoad2(path);
            double quality = -1.0;
            if (checkQuality) {
                quality = music.InspectSuggestQuality();
                qualityAccum += quality;
                ++qualityTestCount;
                using (StreamWriter sw = new StreamWriter(File.Open(qualityOutputPath, FileMode.Append))) {
                    sw.WriteLine("{0} {1:F2}", path, Math.Sqrt(quality));
                }
            }
            return music;
        }

        public void Log転調(string fileName, Music music) {
            Chord prev = null;

            for (int i = 0; i < music.GetNumOfChords(); ++i) {
                Chord chord = music.GetChord(i);
                if (prev != null) {
                    if (chord.KeyRelation != prev.KeyRelation) {
                        using (StreamWriter sw = new StreamWriter(File.Open(modulationLogPath, FileMode.Append))) {
                            MusicKey prevChordKey =  MusicKeyInfo.MusicKeyAndChordDegreeToInternalKey(prev.ActualKey, prev.ChordDegree);
                            KeyRelation kr = MusicKeyInfo.MainKeynameAndChordKeynametoKeyRelation(prevChordKey, chord.ActualKey);
                            KeyRelationInfo kri = new KeyRelationInfo(kr);

                            sw.WriteLine("{0}: {1}調の{2}の和音→{3}調の{4}の和音。 {1}調の{2}⇒{5}調のI→ {5}調の{6}調である{3}調の{4}の和音に転調。",
                                fileName,
                                prev.ActualKey,  prev.ChordDegree,
                                chord.ActualKey, chord.ChordDegree,
                                prevChordKey, kri.DispString());
                        }
                    }
                }
                prev = chord;
            }
        }

        public int Test断片的連結(Music music) {

            int failCount = 0;
            for (int i = 1; i < music.GetNumOfChords(); ++i) {
                Chord chord = music.GetChord(i);
                if (chord.Verdict <= VerdictValue.NotSoGood) {
                    ++failCount;
                }
            }
            return failCount;
        }

        public int Test課題の実施(Music music) {
            int failCount = 0;
            for (int i = 0; i < music.GetNumOfChords(); ++i) {
                Chord chord = music.GetChord(i);
                if (chord.Verdict <= VerdictValue.NotSoGood) {
                    ++failCount;
                }
            }
            return failCount;
        }
        public int Test断片的連結(string path) {
            var music = ReadFphAndCreateMusic(false, path);
            return Test断片的連結(music);
        }

        public int Test課題の実施(string path) {
            var music = ReadFphAndCreateMusic(true, path);
            Log転調(Path.GetFileNameWithoutExtension(path), music);
            return Test課題の実施(music);
        }
    }
}
